using System;
using System.Collections.Generic;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.Util;
using JetBrains.ReSharper.TaskRunnerFramework;
using JetBrains.ReSharper.UnitTestExplorer;

namespace JamesKovacs.ReSharper.UnitTestSupport.VstsUnit {
    public class VstsUnitTestElement : VstsUnitElementBase {
        // Fields
        private readonly VstsUnitTestFixtureElement m_Fixture;
        private readonly string m_MethodName;
        private readonly int m_Order;

        // Methods
        public VstsUnitTestElement(IUnitTestProvider provider, VstsUnitTestFixtureElement fixture, IProject project, string declaringTypeName, string methodName, int order) : base(provider, fixture, project, declaringTypeName) {
            m_Fixture = fixture;
            m_Order = order;
            m_MethodName = methodName;
        }

        public override bool Equals(object obj) {
            if(base.Equals(obj)) {
                VstsUnitTestElement element = (VstsUnitTestElement)obj;
                if(Equals(m_Fixture, element.m_Fixture)) {
                    return (m_MethodName == element.m_MethodName);
                }
            }
            return false;
        }

        public override IDeclaredElement GetDeclaredElement() {
            ITypeElement declaredType = GetDeclaredType();
            if(declaredType != null) {
                foreach(ITypeMember member in MiscUtil.EnumerateMembers(declaredType, m_MethodName, true)) {
                    IMethod method = member as IMethod;
                    if((method != null) && (!method.IsAbstract) && (method.TypeParameters.Length <= 0) && (method.AccessibilityDomain.DomainType == AccessibilityDomain.AccessibilityDomainType.PUBLIC)) {
                        return member;
                    }
                }
            }
            return null;
        }

        public override int GetHashCode() {
            int result = base.GetHashCode();
            result = (0x1d*result) + m_Fixture.GetHashCode();
            return ((0x1d*result) + m_MethodName.GetHashCode());
        }

        public override string GetKind() {
            return "VSTS Test Method";
        }

        public override string GetTitle() {
            return string.Format("{0}.{1}", m_Fixture.GetTitle(), m_MethodName);
        }

        public override bool Matches(string filter) {
            return (m_Fixture.Matches(filter) || (m_MethodName.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) != -1));
        }

        // Properties
        public VstsUnitTestFixtureElement Fixture {
            get { return m_Fixture; }
        }

        public string MethodName {
            get { return m_MethodName; }
        }

        public int Order {
            get { return m_Order; }
        }

        public override IList<UnitTestTask> GetTaskSequence(IList<UnitTestElement> explicitElements) {
            VstsUnitTestFixtureElement parentFixture = this.Fixture;
            return new UnitTestTask[] {
                                          new UnitTestTask(null, new IsolatedAssemblyTask(parentFixture.AssemblyLocation)),
                                          new UnitTestTask(parentFixture, new VstsUnitTestFixtureTask(parentFixture.AssemblyLocation, parentFixture.GetTypeClrName(), explicitElements.Contains(parentFixture))),
                                          new UnitTestTask(this, new VstsUnitTestTask(parentFixture.GetTypeClrName(), this.MethodName, explicitElements.Contains(this)))
                                      };
        }
    }
}